#  arp_daemon.rb
#
#  This file is part of myvnet.
#
#  Copyright (C) 2008  Filipe David Borba Manana,  fdmanana@gmail.com
#
#  myvnet is free software: you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation, either version 3 of the License, or
#  (at your option) any later version.
#
#  myvnet is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with myvnet.  If not, see <http://www.gnu.org/licenses/>.
 

require 'lib/daemons/generic_daemon'


module Daemon
  
  # A daemon whose purpose is to reply to ARP request packets,
  # destined to a given list of network addresses, with ARP reply
  # packets for a given hardware address.
  #
  class ArpDaemon < Daemon::GenericDaemon
    
    
    # === Synopsis
    #
    #   Daemon::ArpDaemon.new(name, packet_injector, hwaddress [, net_address]*)
    #   
    # === Args
    # 
    # +name+::
    #   Name to assign to the daemon. See Daemon::Generic.
    #   
    # +packet_injector+::
    #   Instance of Packet::Injector. Used for injecting packets into the network.
    #   
    # +hwaddress+::
    #   Hardware address to place in the SHA (Sender Hardware Address)
    #   field of ARP reply packets injected into the network by this
    #   daemon. Also the hardware address of the network interface through
    #   which packets are injected into the network.
    #   
    # +net_addresses+::
    #   List of network addresses (IP addresses) this daemon is
    #   interested in as values for the TPA field (Target Protocol
    #   Address) of received ARP request packets.
    # 
    # === Return
    # 
    # A new Daemon::ArpDaemon instance.
    # 
    # === Description
    # 
    # Instantiates a Daemon::ArpDaemon.
    #
    def initialize(name, packet_injector, hwaddress, *net_addresses)
      super
      
      @packet_filter = ""
      @net_addresses.each do |addr|
        @packet_filter << "(arp and dst host #{addr}) or "
      end      
      @packet_filter[-4,4] = ''
            
    end
    
   
    def process(packet)
      return unless packet.has_arp?
      
      arp_req = packet.payload
      
      unless arp_req.oper == :request and @net_addresses.include? arp_req.tpa
        return
      end
      
      eth_reply = packet.dup
      eth_reply.dst = packet.src
      eth_reply.src = @hwaddress
      
      arp_reply = eth_reply.payload
      arp_reply.oper = :reply
      arp_reply.sha = @hwaddress
      arp_reply.spa = arp_req.tpa
      arp_reply.tha = arp_req.sha
      arp_reply.tpa = arp_req.spa
      
      inject eth_reply
      
      true # packet processed
    end

        
  end
end
